﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Happy.ExtentionMethods;
using Happy.Domain;
using Happy.Examples.OrderManagement.Domain.Orders.States;

namespace Happy.Examples.OrderManagement.Domain.Orders
{
    public class Order : AggregateRoot<Guid>
    {
        private OrderState _state;

        /// <summary>
        /// 此构造方法在ORM重建实例的时刻调用。
        /// </summary>
        protected Order() { }

        /// <summary>
        /// 此构成方法会被工厂调用。
        /// </summary>
        internal Order(string orderCode, CustomerInfo customerInfo)
        {
            orderCode.MustNotNullAndNotWhiteSpace("orderCode");
            customerInfo.MustNotNull("customerInfo");

            this.OrderCode = orderCode;
            this.CustomerInfo = customerInfo;
            this.OrderItemCollection = new List<OrderItem>();
            this.CreatedDate = DateTime.Now;
            this.State = OrderStateFactory.Create(this, OrderStatus.New);
        }

        public string OrderCode { get; private set; }

        public CustomerInfo CustomerInfo { get; private set; }

        protected internal virtual ICollection<OrderItem> OrderItemCollection { get; protected set; }

        public OrderItem[] OrderItems { get { return this.OrderItemCollection.ToArray(); } }

        public Decimal Total { get; private set; }

        public DateTime CreatedDate { get; private set; }

        public DateTime? AuditedDate { get; private set; }

        public OrderStatus Status { get; private set; }

        private OrderState State
        {
            get
            {
                if (_state == null)
                {
                    _state = OrderStateFactory.Create(this, this.Status);
                }

                return _state;
            }
            set
            {
                _state = value;
                this.Status = value.Status;
            }
        }

        public void ChangeCustomerInfo(CustomerInfo customerInfo)
        {
            customerInfo.MustNotNull("customerInfo");

            this.State.BeforeChangeOrder();

            this.CustomerInfo = customerInfo;
        }

        public void AddOrderItem(OrderItem item)
        {
            item.MustNotNull("item");

            this.State.BeforeChangeOrder();

            item.OrderId = this.Id;
            this.OrderItemCollection.Add(item);
            this.Total += item.Subtotal;
        }

        public void RemoveOrderItem(Guid productId)
        {
            this.State.BeforeChangeOrder();

            var item = this.OrderItemCollection.First(x => x.ProductId == productId);
            this.OrderItemCollection.Remove(item);
            this.Total -= item.Subtotal;
        }

        public void UpdateOrderItem(Guid productId, int quantity)
        {
            var item = this.OrderItemCollection.First(x => x.ProductId == productId);

            this.Total -= item.Subtotal;
            item.ChangeQuantity(quantity);
            this.Total += item.Subtotal;
        }

        public void Save()
        {
            this.State.Save();
        }

        public void Submit()
        {
            this.State.Submit();
        }

        public void Audit()
        {
            this.State.Audit();
        }

        internal void MarkAsSaved()
        {
            this.State = OrderStateFactory.Create(this, OrderStatus.Saved);
        }

        internal void MarkAsAuditing()
        {
            this.State = OrderStateFactory.Create(this, OrderStatus.Auditing);
        }

        internal void MarkAsAudited()
        {
            this.State = OrderStateFactory.Create(this, OrderStatus.Audited);
            this.AuditedDate = DateTime.Now;
        }
    }
}
